﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Jinjia.Approve.Common.Enum;
using Jinjia.Approve.IRepository.JJFlow;
using Jinjia.Approve.IService;
using Jinjia.Approve.IService.JJFlow;
using Jinjia.Approve.IService.JJFlow.Action;
using Jinjia.Approve.Model.VM;
using Jinjia.Approve.Model.VM.JJFlow;
using Jinjia.Approve.Model.VM.JJFlow.DTO;
using JinJia.Core.Base.Exceptions;
using JinJia.Core.Base.Service;

namespace Jinjia.Approve.Service.JJFlow.Action
{
    public class JJFLowActionCreate : JJFlowActionGoTo, IJJFLowActionCreate
    {
        private readonly IJJFlowNodeService _jjFlowNodeService;
        private readonly IJJFlowTemplateService _jjFlowTemplateService;
        private readonly IJJFlowCommentService _jjFlowCommentService;
        private readonly IFlowInstanceEmpRepository _flowInstanceEmpRepository;
        private readonly IFlowDicCodeRepository _flowDicCodeRepository;
        private readonly IDistributedLockService _distributedLockService;

        public JJFLowActionCreate(IJJFlowInstanceService jjFlowInstanceService,
            IJJFlowTrackService jjFlowTrackService,
            IJJFlowNodeService jjFlowNodeService,
            IJJFlowTemplateService jjFlowTemplateService,
            IJJFlowCommentService jjFlowCommentService,
            IFlowInstanceEmpRepository flowInstanceEmpRepository,
            IFlowDicCodeRepository flowDicCodeRepository,
            IDistributedLockService distributedLockService) : base(jjFlowInstanceService,
            jjFlowTrackService)
        {
            _jjFlowNodeService = jjFlowNodeService;
            _jjFlowTemplateService = jjFlowTemplateService;
            _jjFlowCommentService = jjFlowCommentService;
            _flowInstanceEmpRepository = flowInstanceEmpRepository;
            _flowDicCodeRepository = flowDicCodeRepository;
            _distributedLockService = distributedLockService;
        }

        public async Task<NodeInfo> Create(string modular_key, int template_id, string biz_order_id, int user_id, Dictionary<string, string> form)
        {
            NodeInfo result = null;
            var key = $"fangxing:approve_cache:JJFlow_{nameof(Create)}.{modular_key}_{template_id}_{biz_order_id}_{user_id}";
            
            await _distributedLockService.TryAcquireLockAsync(key, () =>
            {
                result = GetNodeInfo(modular_key, template_id, biz_order_id, user_id, form).GetAwaiter().GetResult();
            }, () =>
            {
                var template = _jjFlowTemplateService.GetTemplateById(template_id).GetAwaiter().GetResult();
                throw new BusinessException($"{template?.TemplateName}审批流，业务单据号：{biz_order_id}重复提交！");
            });
            
            return await Task.FromResult(result);
        }

        private async Task<NodeInfo> GetNodeInfo(string modular_key, int template_id, string biz_order_id, int user_id, Dictionary<string, string> form)
        {
            //此业务是否存在待审批或已经完成的审批记录
            var list = await IsExist(modular_key, template_id, biz_order_id);
            if (list != null && list.Count > 0)
            {
                var jjFlowInstanceVm = list.First();
                var info_old = new NodeInfo
                {
                    instance_id = jjFlowInstanceVm.Id,
                    isComplete = false
                };
                //获取下一个节点
                var next_node = await _jjFlowNodeService.GetNextNode(jjFlowInstanceVm.Id, jjFlowInstanceVm.CurrentNodeId);
                info_old.info = new BaseBoVM<Node>(next_node);
                info_old.emp_user = await GetInstanceNodeEmp(next_node.id, jjFlowInstanceVm.Id, template_id);
                return info_old;
            }

            var jjFlow = new JJFlowCreationRequest
            {
                TemplateId = template_id,
                StartUser = user_id,
                biz_order_id = biz_order_id,
                ModularKey = modular_key
            };
            var info = await CreateFlowInstance(jjFlow, form);
            return info;
        }

        /// <summary>
        /// 此业务是否存在待审批或已经完成的审批记录
        /// </summary>
        /// <param name="modular_key">模块Key</param>
        /// <param name="template_id">审批流模板ID</param>
        /// <param name="biz_order_id">业务ID</param>
        /// <returns></returns>
        public async Task<List<JjFlowInstanceVM>> IsExist(string modular_key, int template_id, string biz_order_id)
        {
            var jjFlowInstanceVms = await _jjFlowInstanceService.IsExist(modular_key, template_id, biz_order_id);
            return jjFlowInstanceVms;
        }

        /// <summary>
        /// 发起申请
        /// </summary>
        /// <param name="request">申请信息</param>
        /// <param name="dic">表单信息</param>
        /// <returns></returns>
        public async Task<NodeInfo> CreateFlowInstance(JJFlowCreationRequest request, Dictionary<string, string> dic = null)
        {
            //找到template
            var template = await _jjFlowTemplateService.GetTemplateById(request.TemplateId);
            if (template == null)
            {
                throw new BusinessException("未找到该审批流信息！");
            }

            var start_node = await _jjFlowNodeService.GetStartNode(template.Id);
            var jjFlowInstanceVm = new JjFlowInstanceVM()
            {
                TemplateId = request.TemplateId,
                StartUser = request.StartUser,
                Remark = request.remark,
                OperationType = request.OperationType,
                BizOrderId = request.biz_order_id,
                CurrentNodeId = start_node.id, //指定当前的节点位置（起始位置）
                CreateUserId = request.StartUser,
                CreateTime = DateTime.Now,
                UpdateUserId = request.StartUser,
                UpdateTime = DateTime.Now,
                Status = "0",
                ModularKey = request.ModularKey
            };

            var id = await _jjFlowInstanceService.Save(jjFlowInstanceVm);

            //保存表单信息
            if (dic != null)
            {
                var dicCodeList = await _flowDicCodeRepository.GetListByTemplateId(request.TemplateId);
                await _jjFlowInstanceService.SaveInstanceForm(id, dic, dicCodeList);
            }

            //确定path
            await _jjFlowNodeService.DecidePath(request.biz_order_id, start_node, request.StartUser.ToString(), id);

            await _jjFlowTrackService.Save(new JjFlowTrackVM()
            {
                node_id = start_node.id,
                node_name = start_node.node_name,
                action_type = 1,
                action_type_name = "发起申请",
                from_emp = request.StartUser.ToString(),
                create_user_id = request.StartUser,
                instance_id = id,
                operation_result = (int)EnumDb.JJFlowOperationTypeEnum.Start,
                create_time = DateTime.Now
            });

            await _jjFlowCommentService.Save(new JJFlowCommentVM()
            {
                comment = request.remark,
                node_name = start_node.node_name,
                node_action = "发起审批",
                is_append = 0,
                biz_order_id = request.biz_order_id,
                modular_key = request.ModularKey,
                create_time = DateTime.Now,
                update_time = DateTime.Now,
                update_user_id = request.StartUser,
                create_user_id = request.StartUser,
            });

            await _jjFlowCommentService.UpdateIsAppend(request.biz_order_id, request.ModularKey);

            //生成节点人员信息
            await _jjFlowInstanceService.SaveInstanceEmp(id, request.TemplateId, request.biz_order_id, request.StartUser, dic);

            //获取下一个节点
            var next_node = await _jjFlowNodeService.GetNextNode(id, start_node.id);
            var info = new NodeInfo
            {
                instance_id = id,
                isComplete = false,
                info = new BaseBoVM<Node>(next_node),
                emp_user = await GetInstanceNodeEmp(next_node.id, id, request.TemplateId)
            };
            return info;
        }

        public async Task<List<EmpInfo>> GetInstanceNodeEmp(int node_id, int instance_id, int template_id)
        {
            var instanceNodeEmp = await _flowInstanceEmpRepository.GetInstanceNodeEmp(node_id, instance_id, template_id);
            return instanceNodeEmp;
        }
    }
}